<?php

namespace fastphp;

use fastphp\util\Log;

/**
 * 配置管理类
 * 支持加载配置文件和通过点号语法访问嵌套配置项
 */
class Config
{
    /**
     * 配置数据
     * @var array
     */
    protected array $config = [];
    
    /**
     * 已加载的配置文件
     * @var array
     */
    protected array $loadedFiles = [];
    
    /**
     * 构造函数
     * @param array $config 初始配置数组（可选）
     */
    public function __construct(array $config = [])
    {
        // 初始化配置数据
        $this->config = $config;
        
        // 如果存在全局配置，则合并
        if (isset($GLOBALS['config']) && is_array($GLOBALS['config'])) {
            $this->config = array_merge($this->config, $GLOBALS['config']);
        }
        
        // 自动加载配置文件夹中的所有配置文件
        $this->autoLoadConfig();
    }
    
    /**
     * 自动加载配置文件夹中的所有配置文件
     */
    public function autoLoadConfig()
    {
        $configDir = CONFIG_PATH;
        if (is_dir($configDir)) {
            // 获取所有.php配置文件
            $files = glob($configDir . '*.php');
            foreach ($files as $file) {
                $filename = basename($file, '.php');
                // 移除排除条件，允许加载所有.php文件
                $this->load($file, $filename);
            }
        }
    }
    
    /**
     * 加载配置文件
     * @param string $file 配置文件路径
     * @param string $prefix 配置前缀（可选）
     * @return bool 是否加载成功
     */
    public function load(string $file, string $prefix = ''): bool
    {
        // 检查文件是否存在
        if (!is_file($file)) {
            Log::error("配置文件不存在: {$file}", 'config');
            return false;
        }
        
        // 检查文件是否已经加载过
        if (in_array($file, $this->loadedFiles)) {
            return true;
        }
        
        try {
            // 加载配置文件
            $config = require $file;
            
            // 检查是否返回数组
            if (!is_array($config)) {
                Log::error("配置文件必须返回数组: {$file}", 'config');
                return false;
            }
            
            // 根据前缀决定如何合并配置
            if ($prefix) {
                $this->config[$prefix] = array_merge($this->config[$prefix] ?? [], $config);
            } else {
                $this->config = array_merge($this->config, $config);
            }
            
            // 记录已加载的文件
            $this->loadedFiles[] = $file;
            
            Log::debug("配置文件加载成功: {$file}", 'config');
            return true;
        } catch (\Throwable $e) {
            Log::error("配置文件加载失败: {$file}, 错误: " . $e->getMessage(), 'config');
            return false;
        }
    }
    
    /**
     * 通过点号语法获取配置项
     * @param string $key 配置键名，支持点号分隔的嵌套键名
     * @param mixed $default 默认值（当配置项不存在时返回）
     * @return mixed 配置值或默认值
     */
    public function get(string $key, $default = null)
    {
        // 如果为空键名，返回所有配置
        if (empty($key)) {
            return $this->config;
        }
        
        // 分割键名
        $keys = explode('.', $key);
        $value = $this->config;
        
        // 遍历键名路径
        foreach ($keys as $k) {
            // 检查当前层级是否存在该键
            if (!isset($value[$k])) {
                return $default;
            }
            // 进入下一层级
            $value = $value[$k];
        }
        
        return $value;
    }
    
    /**
     * 设置配置项
     * @param string $key 配置键名，支持点号分隔的嵌套键名
     * @param mixed $value 配置值
     * @return $this
     */
    public function set(string $key, $value): self
    {
        // 如果为空键名，直接替换所有配置
        if (empty($key)) {
            $this->config = $value;
            return $this;
        }
        
        // 分割键名
        $keys = explode('.', $key);
        $config = &$this->config;
        
        // 遍历键名路径，创建不存在的层级
        $lastKey = array_pop($keys);
        foreach ($keys as $k) {
            if (!isset($config[$k]) || !is_array($config[$k])) {
                $config[$k] = [];
            }
            $config = &$config[$k];
        }
        
        // 设置最终值
        $config[$lastKey] = $value;
        
        return $this;
    }
    
    /**
     * 检查配置项是否存在
     * @param string $key 配置键名，支持点号分隔的嵌套键名
     * @return bool 是否存在
     */
    public function has(string $key): bool
    {
        // 分割键名
        $keys = explode('.', $key);
        $value = $this->config;
        
        // 遍历键名路径
        foreach ($keys as $k) {
            // 检查当前层级是否存在该键
            if (!isset($value[$k])) {
                return false;
            }
            // 进入下一层级
            $value = $value[$k];
        }
        
        return true;
    }
    
    /**
     * 移除配置项
     * @param string $key 配置键名，支持点号分隔的嵌套键名
     * @return $this
     */
    public function remove(string $key): self
    {
        // 分割键名
        $keys = explode('.', $key);
        $config = &$this->config;
        
        // 遍历键名路径
        $keyPath = [];
        foreach ($keys as $k) {
            $keyPath[] = $k;
            if (!isset($config[$k])) {
                return $this; // 键不存在，直接返回
            }
            $currentKey = &$config[$k];
            $config = &$currentKey;
        }
        
        // 重建数组，移除目标键
        $parentConfig = &$this->config;
        $lastKey = array_pop($keys);
        foreach ($keys as $k) {
            $parentConfig = &$parentConfig[$k];
        }
        unset($parentConfig[$lastKey]);
        
        return $this;
    }
    
    /**
     * 获取所有配置
     * @return array 所有配置
     */
    public function all(): array
    {
        return $this->config;
    }
    
    /**
     * 清空所有配置
     * @return $this
     */
    public function clear(): self
    {
        $this->config = [];
        $this->loadedFiles = [];
        return $this;
    }
    
    /**
     * 获取已加载的配置文件列表
     * @return array 已加载的配置文件路径
     */
    public function getLoadedFiles(): array
    {
        return $this->loadedFiles;
    }
}